package com.sinosoft.dsp.component.bpm.facade.engine;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.NoneScoped;

import org.jbpm.api.Deployment;
import org.jbpm.api.ProcessDefinition;
import org.jbpm.api.ProcessDefinitionQuery;
import org.jbpm.xsdobject.Process;

import com.sinosoft.dsp.component.bpm.util.JbpmConfig;
import com.sinosoft.dsp.component.bpm.util.ProcessParse;
import com.sinosoft.dsp.component.bpm.viewbean.BpmConfigViewBean;
import com.sinosoft.dsp.platform.utils.SinoManagedBean;
import com.sinosoft.dsp.system.core.log.Log;
import com.sinosoft.dsp.system.utils.Const;
import com.sinosoft.dsp.system.utils.StringUtil;

/**
 * 流程的资源管理服务门面<br>
 * 目录-部署-流程定义<br>
 * 部署项目会有资源，其中一种资源就是流程定义，所以需要通过部署的id和资源名称来找到流程定义
 * 
 * @author lichanghao
 * 
 */
@ManagedBean(name = "processResourceFacade")
@NoneScoped
public class ProcessResourceFacade {

	private static final Log log = Log.getLog(ProcessResourceFacade.class
			.getName());

	/**
	 * 创建部署
	 * 
	 * @param name
	 * @param parentId
	 */
	public String createDeployment(String name, long parentId) {
		JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
		String directoryid = jbpmConfig.getRepositoryService()
				.createDeployment().setName(name).setParentDeploymentId(
						parentId).deploy();

		log.debug("创建部署：ID为" + directoryid);
		return directoryid;
	}

	/**
	 * 更新部署名称
	 * 
	 * @param deploymentId
	 * @param name
	 */
	public boolean updateDeployment(String deploymentId, String name) {
		log.debug("更新部署名称：ID为" + deploymentId + "，NAME为" + name);
		try {
			JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
			jbpmConfig.getRepositoryService().updateDeployment(deploymentId,
					name);
		} catch (Exception e) {
			log.error("更新部署名称出现错误：ID为" + deploymentId + "，NAME为" + name);
			return false;
		}
		return true;
	}

	/**
	 * 删除部署
	 * 
	 * @param deploymentId
	 * @return
	 */
	public boolean deleteDeployment(String deploymentId) {
		log.debug("删除部署：ID为" + deploymentId);
		try {
			JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
			jbpmConfig.getRepositoryService().deleteDeployment(deploymentId);
		} catch (Exception e) {
			log.error("删除部署：ID为" + deploymentId);
			return false;
		}
		return true;
	}

	/**
	 * 检查重复的资源名称
	 * 
	 * @return
	 */
	public boolean checkDuplicateResourceName(String deploymentId,
			String resourceName) {
		log.debug("检查重复的资源名称：ID为" + deploymentId + "，资源名为" + resourceName);

		try {
			JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
			Set<String> names = jbpmConfig.getRepositoryService()
					.getResourceNames(deploymentId);
			if (names != null) {
				for (String n : names) {
					if (n.equals(resourceName)) {
						return true;
					}
				}
			}
		} catch (Exception e) {
			log.error("检查重复的资源名称出现错误：ID为" + deploymentId + "，资源名为"
					+ resourceName);
		}
		return false;
	}

	/**
	 * 获得部署中的资源内容
	 * 
	 * @param deploymentId
	 * @param resourceName
	 * @return
	 */
	public String getDeploymentResource(String deploymentId, String resourceName) {
		log.debug("获得部署中的资源内容：ID为" + deploymentId + "，资源名为" + resourceName);
		InputStream is = null;
		ByteArrayOutputStream baos = null;
		try {
			JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
			is = jbpmConfig.getRepositoryService().getResourceAsStream(
					deploymentId, resourceName);
			if (is == null) {
				return "";
			}
			baos = new ByteArrayOutputStream();
			int i = -1;
			while ((i = is.read()) != -1) {
				baos.write(i);
			}
			return baos.toString();

		} catch (Exception e) {
			log.error("获得部署中的资源内容出现错误：ID为" + deploymentId + "，资源名为"
					+ resourceName);
			return "";
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					log.error("无法关闭流");
				}
			}

			if (baos != null) {
				try {
					baos.close();
				} catch (IOException e) {
					log.error("无法关闭流");
				}
			}
		}
	}

	/**
	 * 修改部署资源的名称及子资源名称路径
	 * 
	 * @param deploymentId
	 * @param initResourceName
	 * @param resourceName
	 * @return
	 */
	public boolean renameDeploymentResourceName(String deploymentId,
			String initResourceName, String resourceName) {
		log.debug("修改部署资源的名称及子资源名称路径：ID为" + deploymentId + "，原始资源名为"
				+ initResourceName + "，新资源名为" + resourceName);
		try {
			JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
			jbpmConfig.getRepositoryService().renameDeploymentResourceName(
					deploymentId, initResourceName, resourceName);
		} catch (Exception e) {
			log.error("修改部署资源的名称及子资源名称路径出现错误：ID为" + deploymentId + "，原始资源名为"
					+ initResourceName + "，新资源名为" + resourceName);
			return false;
		}
		return true;
	}

	/**
	 * 创建或更新部署中的资源
	 * 
	 * @param deploymentId
	 * @param resourceName
	 * @param text
	 */
	public boolean createOrUpdateDeploymentResource(String deploymentId,
			String resourceName, String text) {
		log.debug("更新部署的资源：ID为" + deploymentId + "，资源名为" + resourceName);
		try {
			InputStream is = StringUtil.str2is(Const.NVL(text, ""));
			JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
			jbpmConfig.getRepositoryService().updateDeploymentResource(
					deploymentId, resourceName, is);
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					log.error("无法关闭流");
				}
			}
		} catch (Exception e) {
			log
					.error("更新部署的资源出现错误：ID为" + deploymentId + "，资源名为"
							+ resourceName);
			return false;
		}

		return true;
	}

	public boolean deleteDeploymentResource(String deploymentId,
			String resourceName) {
		log.debug("删除部署的资源：ID为" + deploymentId + "，资源名为" + resourceName);
		try {
			JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
			jbpmConfig.getRepositoryService().deleteDeploymentResource(
					deploymentId, resourceName);
		} catch (Exception e) {
			log
					.error("更新部署的资源出现错误：ID为" + deploymentId + "，资源名为"
							+ resourceName);
			return false;
		}

		return true;
	}

	/**
	 * 通过流程对象，部署流程定义
	 * 
	 * @param process流程定义对象
	 * @return 流程部署ID
	 */
	public String createOrUpdateProcess(Process process) {
		JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
		String processStr = ProcessParse.objectToXmlOfProcess(process);
		String deploymentId = jbpmConfig.getRepositoryService()
				.createDeployment().addResourceFromString(process.getName(),
						processStr).deploy();
		log.debug("创建流程：ID为" + deploymentId);
		return deploymentId;
	}

	/**
	 * 通过jpdl文件，部署流程定义
	 * 
	 * @param path
	 * @return 流程部署ID
	 */
	public String createOrUpdateProcess(String path) {
		JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
		String deploymentid = jbpmConfig.getRepositoryService()
				.createDeployment().addResourceFromClasspath(path).deploy();
		log.debug("创建流程：ID为" + deploymentid);
		return deploymentid;
	}

	/**
	 * 删除流程定义
	 * 
	 * @param processId流程Id
	 */
	public boolean deleteProcess(String processId) {
		log.debug("删除流程：ID为" + processId);
		try {
			JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
			jbpmConfig.getRepositoryService().deleteDeployment(processId);
		} catch (Exception e) {
			log.error("删除流程出现错误：ID为" + processId);
			return false;
		}
		return true;
	}

	/**
	 * 通过部署ID和资源名称，获取流程定义对象
	 * 
	 * @param processId
	 *            流程Id
	 */
	public ProcessDefinition findProcessDefinition(String deploymentId,
			String name) {
		JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
		return jbpmConfig.getRepositoryService().createProcessDefinitionQuery()
				.deploymentId(deploymentId).processDefinitionName(name)
				.uniqueResult();
	}

	public ProcessDefinition findProcessDefinition(String pdId) {
		JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
		return jbpmConfig.getRepositoryService().createProcessDefinitionQuery()
				.processDefinitionId(pdId).uniqueResult();
	}

	/**
	 * 通过部署的ID，得到最新流程定义列表
	 * 
	 * @param pid
	 *            部署的ID
	 */
	public List<ProcessDefinition> queryLatestActiveProcessDefinitionByParentId(
			String pid) {
		JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
		List<ProcessDefinition> processDefinitions = jbpmConfig
				.getRepositoryService().createProcessDefinitionQuery()
				.deploymentId(pid).notSuspended().orderAsc(
						ProcessDefinitionQuery.PROPERTY_NAME).list();
		return distributeProcessDefinition(processDefinitions);
	}

	public List<ProcessDefinition> queryLatestActiveProcessDefinition() {
		JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
		List<ProcessDefinition> processDefinitions = jbpmConfig
				.getRepositoryService().createProcessDefinitionQuery()
				.notSuspended().orderAsc(ProcessDefinitionQuery.PROPERTY_NAME)
				.list();
		return distributeProcessDefinition(processDefinitions);
	}

	/**
	 * 自动判断系统的BPM部署方案，获得最新的流程定义列表
	 * 
	 * @return
	 */
	public List<ProcessDefinition> queryLatestActiveProcessDefinitionAuto() {
		// 判断BPM部署的方式
		if ("singleton".equalsIgnoreCase(BpmConfigViewBean.deployType)) {
			return queryLatestActiveProcessDefinitionByParentId(BpmConfigViewBean.deployId);
		} else {
			return queryLatestActiveProcessDefinition();
		}
	}

	/**
	 * 去除重复的流程定义，获得最新的流程定义
	 * 
	 * @param processDefinitions
	 * @return
	 */
	private List<ProcessDefinition> distributeProcessDefinition(
			List<ProcessDefinition> processDefinitions) {
		Map<String, ProcessDefinition> map = new LinkedHashMap<String, ProcessDefinition>();
		for (ProcessDefinition pd : processDefinitions) {
			String key = pd.getKey();
			ProcessDefinition definition = map.get(key);
			if ((definition == null)
					|| (definition.getVersion() < pd.getVersion())) {
				map.put(key, pd);
			}
		}
		return new ArrayList<ProcessDefinition>(map.values());
	}

	/**
	 * 通过目录ID获得其下的所有可用的部署
	 * 
	 * @param pid
	 * @return
	 */
	public List<Deployment> queryActiveDeploymentByParentId(String pid) {
		JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
		return jbpmConfig.getRepositoryService().createDeploymentQuery()
				.notSuspended().parentDeploymentId(pid).list();
	}

	/**
	 * 通过目录ID获得一个部署
	 * 
	 * @param id
	 * @return
	 */
	public Deployment queryActiveDeploymentById(String id) {
		JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
		return jbpmConfig.getRepositoryService().createDeploymentQuery()
				.notSuspended().deploymentId(id).uniqueResult();
	}

	public List<Deployment> queryActiveDeployment() {
		JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");
		return jbpmConfig.getRepositoryService().createDeploymentQuery()
				.notSuspended().list();
	}

}
